home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / packer / gnu-tar / extract.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  20KB  |  725 lines

  1. /* Extract files from a tar archive.
  2.    Copyright (C) 1988 Free Software Foundation
  3.  
  4. This file is part of GNU Tar.
  5.  
  6. GNU Tar is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Tar is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Tar; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * Extract files from a tar archive.
  22.  *
  23.  * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  24.  *
  25.  * @(#) extract.c 1.32 87/11/11 - gnu
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32.  
  33. #ifdef BSD42
  34. #include <sys/file.h>
  35. #endif
  36.  
  37. #ifdef USG
  38. #include <fcntl.h>
  39. #endif
  40.  
  41. #ifdef    MSDOS
  42. #include <fcntl.h>
  43. #endif    /* MSDOS */
  44.  
  45. /*
  46.  * Some people don't have a #define for these.
  47.  */
  48. #ifndef O_BINARY
  49. #define O_BINARY    0
  50. #endif
  51. #ifndef O_NDELAY
  52. #define O_NDELAY    0
  53. #endif
  54.  
  55. #ifdef NO_OPEN3
  56. /* We need the #define's even though we don't use them. */
  57. #include "open3.h"
  58. #endif
  59.  
  60. #ifdef EMUL_OPEN3
  61. /* Simulated 3-argument open for systems that don't have it */
  62. #include "open3.h"
  63. #endif
  64.  
  65. extern int errno;            /* From libc.a */
  66. #ifndef AMIGA
  67. extern time_t time();                   /* From libc.a */
  68. #endif
  69. extern char *index();                   /* From libc.a or port.c */
  70.  
  71. #include "tar.h"
  72. #include "port.h"
  73.  
  74. extern FILE *msg_file;
  75.  
  76. extern union record *head;        /* Points to current tape header */
  77. extern struct stat hstat;        /* Stat struct corresponding */
  78. extern int head_standard;        /* Tape header is in ANSI format */
  79.  
  80. extern char *save_name;
  81. extern long save_totsize;
  82. extern long save_sizeleft;
  83.  
  84. extern void print_header();
  85. extern void skip_file();
  86. extern void skip_extended_headers();
  87. extern void pr_mkdir();
  88.  
  89. int make_dirs();                        /* Makes required directories */
  90.  
  91. static time_t now = 0;            /* Current time */
  92. static we_are_root = 0;         /* True if our effective uid == 0 */
  93. static int notumask = ~0;        /* Masks out bits user doesn't want */
  94.  
  95. /*
  96.  * "Scratch" space to store the information about a sparse file before
  97.  * writing the info into the header or extended header
  98.  */
  99. /*struct sp_array    *sparsearray;*/
  100.  
  101. /* number of elts storable in the sparsearray */
  102. /*int    sp_array_size = 10;*/
  103.  
  104. /*
  105.  * Set up to extract files.
  106.  */
  107. extr_init()
  108. {
  109.     int ourmask;
  110.  
  111.     now = time((time_t *)0);
  112.     if (f_do_chown || geteuid() == 0)
  113.         we_are_root = 1;
  114.  
  115.     /*
  116.      * We need to know our umask.  But if f_use_protection is set,
  117.      * leave our kernel umask at 0, and our "notumask" at ~0.
  118.      */
  119.     ourmask = umask(0);             /* Read it */
  120.     if (!f_use_protection) {
  121.         (void) umask (ourmask); /* Set it back how it was */
  122.         notumask = ~ourmask;    /* Make umask override permissions */
  123.     }
  124. }
  125.  
  126.  
  127. /*
  128.  * Extract a file from the archive.
  129.  */
  130. void
  131. extract_archive()
  132. {
  133.     register char *data;
  134.     int fd, check, namelen, written, openflag;
  135.     long size;
  136.     time_t acc_upd_times[2];
  137.     register int skipcrud;
  138.     register int i;
  139.     int sparse_ind = 0;
  140.     union record *exhdr;
  141.     int end_nulls;
  142.  
  143.     saverec(&head);                 /* Make sure it sticks around */
  144.     userec(head);                   /* And go past it in the archive */
  145.     decode_header(head, &hstat, &head_standard, 1); /* Snarf fields */
  146.  
  147.     if(f_confirm && !confirm("extract",head->header.name)) {
  148.         if (head->header.isextended)
  149.             skip_extended_headers();
  150.         skip_file((long)hstat.st_size);
  151.         saverec((union record **)0);
  152.         return;
  153.     }
  154.  
  155.     /* Print the record from 'head' and 'hstat' */
  156.     if (f_verbose)
  157.         print_header();
  158.  
  159.     /*
  160.      * Check for fully specified pathnames and other atrocities.
  161.      *
  162.      * Note, we can't just make a pointer to the new file name,
  163.      * since saverec() might move the header and adjust "head".
  164.      * We have to start from "head" every time we want to touch
  165.      * the header record.
  166.      */
  167.     skipcrud = 0;
  168.     while (!f_absolute_paths && '/' == head->header.name[skipcrud]) {
  169.         static int warned_once = 0;
  170.  
  171.         skipcrud++;    /* Force relative path */
  172.         if (!warned_once++) {
  173.             msg("Removing leading / from absolute path names in the archive.");
  174.         }
  175.     }
  176.  
  177.     switch (head->header.linkflag) {
  178.  
  179.     default:
  180.         msg("Unknown file type '%c' for %s, extracted as normal file",
  181.             head->header.linkflag, skipcrud+head->header.name);
  182.         /* FALL THRU */
  183.  
  184.     /*
  185.      * JK - What we want to do if the file is sparse is loop through
  186.      * the array of sparse structures in the header and read in
  187.      * and translate the character strings representing  1) the offset
  188.      * at which to write and 2) how many bytes to write into numbers,
  189.      * which we store into the scratch array, "sparsearray".  This
  190.      * array makes our life easier the same way it did in creating
  191.      * the tar file that had to deal with a sparse file.
  192.      *
  193.      * After we read in the first five (at most) sparse structures,
  194.      * we check to see if the file has an extended header, i.e.,
  195.      * if more sparse structures are needed to describe the contents
  196.      * of the new file.  If so, we read in the extended headers
  197.      * and continue to store their contents into the sparsearray.
  198.      */
  199.     case LF_SPARSE:
  200.         sp_array_size = 10;
  201.         sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
  202.         for (i = 0; i < SPARSE_IN_HDR; i++) {
  203.             if (!head->header.sp[i].numbytes)
  204.                 break;
  205.             sparsearray[i].offset =
  206.                 from_oct(1+12, head->header.sp[i].offset);
  207.             sparsearray[i].numbytes =
  208.                 from_oct(1+12, head->header.sp[i].numbytes);
  209.         }
  210.  
  211. /*        end_nulls = from_oct(1+12, head->header.ending_blanks);*/
  212.  
  213.         if (head->header.isextended) {
  214.             /* read in the list of extended headers
  215.                and translate them into the sparsearray
  216.                as before */
  217.  
  218.             /* static */ int ind = SPARSE_IN_HDR;
  219.  
  220.             for (;;) {
  221.  
  222.                 exhdr = findrec();
  223.                 for (i = 0; i < SPARSE_EXT_HDR; i++) {
  224.  
  225.                     if (i+ind > sp_array_size-1) {
  226.                     /*
  227.                      * realloc the scratch area
  228.                      * since we've run out of room --
  229.                      */
  230.                         sparsearray = (struct sp_array *)
  231.                                 realloc(sparsearray,
  232.                                 2 * sp_array_size * (sizeof(struct sp_array)));
  233.                         sp_array_size *= 2;
  234.                     }
  235.                     if (!exhdr->ext_hdr.sp[i].numbytes)
  236.                         break;
  237.                     sparsearray[i+ind].offset =
  238.                         from_oct(1+12, exhdr->ext_hdr.sp[i].offset);
  239.                     sparsearray[i+ind].numbytes =
  240.                         from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes);
  241.                 }
  242.                 if (!exhdr->ext_hdr.isextended)
  243.                     break;
  244.                 else {
  245.                     ind += SPARSE_EXT_HDR;
  246.                     userec(exhdr);
  247.                 }
  248.             }
  249.             userec(exhdr);
  250.         }
  251.  
  252.         /* FALL THRU */
  253.     case LF_OLDNORMAL:
  254.     case LF_NORMAL:
  255.     case LF_CONTIG:
  256.         /*
  257.          * Appears to be a file.
  258.          * See if it's really a directory.
  259.          */
  260.         namelen = strlen(skipcrud+head->header.name)-1;
  261.         if (head->header.name[skipcrud+namelen] == '/')
  262.             goto really_dir;
  263.  
  264.         /* FIXME, deal with protection issues */
  265.     again_file:
  266.         openflag = (f_keep?
  267.             O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
  268.             O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
  269.             | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
  270.             /*
  271.              * JK - The last | is a kludge to solve the problem
  272.              * the O_APPEND flag  causes with files we are
  273.              * trying to make sparse:  when a file is opened
  274.              * with O_APPEND, it writes  to the last place
  275.              * that something was written, thereby ignoring
  276.              * any lseeks that we have done.  We add this
  277.              * extra condition to make it able to lseek when
  278.              * a file is sparse, i.e., we don't open the new
  279.              * file with this flag.  (Grump -- this bug caused
  280.              * me to waste a good deal of time, I might add)
  281.              */
  282.  
  283.         if(f_exstdout) {
  284.             fd = 1;
  285.             goto extract_file;
  286.         }
  287. #ifdef O_CTG
  288.         /*
  289.          * Contiguous files (on the Masscomp) have to specify
  290.          * the size in the open call that creates them.
  291.          */
  292.         if (head->header.linkflag == LF_CONTIG)
  293.             fd = open(skipcrud+head->header.name, openflag | O_CTG,
  294.                 hstat.st_mode, hstat.st_size);
  295.         else
  296. #endif
  297.         {
  298. #ifdef NO_OPEN3
  299.             /*
  300.              * On raw V7 we won't let them specify -k (f_keep), but
  301.              * we just bull ahead and create the files.
  302.              */
  303.             fd = creat(skipcrud+head->header.name,
  304.                 hstat.st_mode);
  305. #else
  306.             /*
  307.              * With 3-arg open(), we can do this up right.
  308.              */
  309.             fd = open(skipcrud+head->header.name, openflag,
  310.                 hstat.st_mode);
  311. #endif
  312.         }
  313.  
  314.         if (fd < 0) {
  315.             if (make_dirs(skipcrud+head->header.name))
  316.                 goto again_file;
  317.             msg_perror("Could not create file %s",skipcrud+head->header.name);
  318.             if (head->header.isextended)
  319.                 skip_extended_headers();
  320.             skip_file((long)hstat.st_size);
  321.             goto quit;
  322.         }
  323.  
  324.     extract_file:
  325.         if (head->header.linkflag == LF_SPARSE) {
  326.             char    *name;
  327.             int    namelen;
  328.  
  329.             /*
  330.              * Kludge alert.  NAME is assigned to header.name
  331.              * because during the extraction, the space that
  332.              * contains the header will get scribbled on, and
  333.              * the name will get munged, so any error messages
  334.              * that happen to contain the filename will look
  335.              * REAL interesting unless we do this.
  336.              */
  337.             namelen = strlen(skipcrud+head->header.name);
  338.             name = (char *) malloc((sizeof(char)) * namelen);
  339.             bcopy(skipcrud+head->header.name, name, namelen);
  340.             size = hstat.st_size;
  341.             extract_sparse_file(fd, &size, hstat.st_size,
  342.                         name);
  343.         }
  344.         else
  345.           for (size = hstat.st_size;
  346.                size > 0;
  347.                size -= written) {
  348.  
  349.             long    offset,
  350.                 numbytes;
  351.  
  352.             if(f_multivol) {
  353.                 save_name=head->header.name;
  354.                 save_totsize=hstat.st_size;
  355.                 save_sizeleft=size;
  356.             }
  357.  
  358.             /*
  359.              * Locate data, determine max length
  360.              * writeable, write it, record that
  361.              * we have used the data, then check
  362.              * if the write worked.
  363.              */
  364.             data = findrec()->charptr;
  365.             if (data == NULL) {     /* Check it... */
  366.                 msg("Unexpected EOF on archive file");
  367.                 break;
  368.             }
  369.             /*
  370.              * JK - If the file is sparse, use the sparsearray
  371.              * that we created before to lseek into the new
  372.              * file the proper amount, and to see how many
  373.              * bytes we want to write at that position.
  374.              */
  375. /*            if (head->header.linkflag == LF_SPARSE) {
  376.                 off_t pos;
  377.  
  378.                 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
  379.                 printf("%d at %d\n", (int) pos, sparse_ind);
  380.                 written = sparsearray[sparse_ind++].numbytes;
  381.             } else*/
  382.             written = endofrecs()->charptr - data;
  383.             if (written > size)
  384.                 written = size;
  385.             errno = 0;
  386.             check = write(fd, data, written);
  387.             /*
  388.              * The following is in violation of strict
  389.              * typing, since the arg to userec
  390.              * should be a struct rec *.  FIXME.
  391.              */
  392.             userec((union record *)(data + written - 1));
  393.             if (check == written) continue;
  394.             /*
  395.              * Error in writing to file.
  396.              * Print it, skip to next file in archive.
  397.              */
  398.             if(check<0)
  399.                 msg_perror("couldn't write to file %s",skipcrud+head->header.name);
  400.             else
  401.                 msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.name);
  402.             skip_file((long)(size - written));
  403.             break;    /* Still do the close, mod time, chmod, etc */
  404.         }
  405.  
  406.         if(f_multivol)
  407.             save_name = 0;
  408.  
  409.             /* If writing to stdout, don't try to do anything
  410.                to the filename; it doesn't exist, or we don't
  411.                want to touch it anyway */
  412.         if(f_exstdout)
  413.             break;
  414.  
  415. /*        if (head->header.isextended) {
  416.             register union record *exhdr;
  417.             register int i;
  418.  
  419.             for (i = 0; i < 21; i++) {
  420.                 long offset;
  421.  
  422.                 if (!exhdr->ext_hdr.sp[i].numbytes)
  423.                     break;
  424.                 offset = from_oct(1+12,
  425.                         exhdr->ext_hdr.sp[i].offset);
  426.                 written = from_oct(1+12,
  427.                         exhdr->ext_hdr.sp[i].numbytes);
  428.                 lseek(fd, offset, 0);
  429.                 check = write(fd, data, written);
  430.                 if (check == written) continue;
  431.  
  432.             }
  433.  
  434.  
  435.         }*/
  436.         check = close(fd);
  437.         if (check < 0) {
  438.             msg_perror("Error while closing %s",skipcrud+head->header.name);
  439.         }
  440.  
  441.  
  442.     set_filestat:
  443.  
  444.         /*
  445.          * If we are root, set the owner and group of the extracted
  446.          * file.  This does what is wanted both on real Unix and on
  447.          * System V.  If we are running as a user, we extract as that
  448.          * user; if running as root, we extract as the original owner.
  449.          */
  450.         if (we_are_root) {
  451.             if (chown(skipcrud+head->header.name, hstat.st_uid,
  452.                   hstat.st_gid) < 0) {
  453.                 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
  454.             }
  455.         }
  456.  
  457.         /*
  458.          * If '-k' is not set, open() or creat() could have saved
  459.          * the permission bits from a previously created file,
  460.          * ignoring the ones we specified.
  461.          * Even if -k is set, if the file has abnormal
  462.          * mode bits, we must chmod since writing or chown() has
  463.          * probably reset them.
  464.          *
  465.          * If -k is set, we know *we* created this file, so the mode
  466.          * bits were set by our open().   If the file is "normal", we
  467.          * skip the chmod.  This works because we did umask(0) if -p
  468.          * is set, so umask will have left the specified mode alone.
  469.          */
  470.         if ((!f_keep)
  471.             || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
  472.             if (chmod(skipcrud+head->header.name,
  473.                   notumask & (int)hstat.st_mode) < 0) {
  474.                 msg_perror("cannot change mode of file %s to %ld",skipcrud+head->header.name,notumask & (int)hstat.st_mode);
  475.             }
  476.         }
  477.         /*
  478.          * Set the modified time of the file.
  479.          *
  480.          * Note that we set the accessed time to "now", which
  481.          * is really "the time we started extracting files".
  482.          * unless f_gnudump is used, in which case .st_atime is used
  483.          */
  484.         if (!f_modified) {
  485.             /* fixme if f_gnudump should set ctime too, but how? */
  486.             if(f_gnudump)
  487.                 acc_upd_times[0]=hstat.st_atime;
  488.             else acc_upd_times[0] = now;         /* Accessed now */
  489.             acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
  490.             if (utime(skipcrud+head->header.name,
  491.                 acc_upd_times) < 0) {
  492.                 msg_perror("couldn't change access and modification times of %s",skipcrud+head->header.name);
  493.             }
  494.         }
  495.  
  496.     quit:
  497.         break;
  498.  
  499.     case LF_LINK:
  500.     again_link:
  501.         check = link (head->header.linkname,
  502.                   skipcrud+head->header.name);
  503.         if (check == 0)
  504.             break;
  505.         if (make_dirs(skipcrud+head->header.name))
  506.             goto again_link;
  507.         if(f_gnudump && errno==EEXIST)
  508.             break;
  509.         msg_perror("Could not link %s to %s",
  510.             skipcrud+head->header.name,head->header.linkname);
  511.         break;
  512.  
  513. #ifdef S_IFLNK
  514.     case LF_SYMLINK:
  515.     again_symlink:
  516.         check = symlink(head->header.linkname,
  517.                 skipcrud+head->header.name);
  518.         /* FIXME, don't worry uid, gid, etc... */
  519.         if (check == 0)
  520.             break;
  521.         if (make_dirs(skipcrud+head->header.name))
  522.             goto again_symlink;
  523.         msg_perror("Could not create symlink to %s",head->header.linkname);
  524.         break;
  525. #endif
  526.  
  527. #ifdef S_IFCHR
  528.     case LF_CHR:
  529.         hstat.st_mode |= S_IFCHR;
  530.         goto make_node;
  531. #endif
  532.  
  533. #ifdef S_IFBLK
  534.     case LF_BLK:
  535.         hstat.st_mode |= S_IFBLK;
  536.         goto make_node;
  537. #endif
  538.  
  539. #ifdef S_IFIFO
  540.     /* If local system doesn't support FIFOs, use default case */
  541.     case LF_FIFO:
  542.         hstat.st_mode |= S_IFIFO;
  543.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  544.         goto make_node;
  545. #endif
  546.  
  547.     make_node:
  548.         check = mknod(skipcrud+head->header.name,
  549.                   (int) hstat.st_mode, (int) hstat.st_rdev);
  550.         if (check != 0) {
  551.             if (make_dirs(skipcrud+head->header.name))
  552.                 goto make_node;
  553.             msg_perror("Could not make %s",skipcrud+head->header.name);
  554.             break;
  555.         };
  556.         goto set_filestat;
  557.  
  558.     case LF_DIR:
  559.     case LF_DUMPDIR:
  560.         namelen = strlen(skipcrud+head->header.name)-1;
  561.     really_dir:
  562.         /* Check for trailing /, and zap as many as we find. */
  563.         while (namelen && head->header.name[skipcrud+namelen] == '/')
  564.             head->header.name[skipcrud+namelen--] = '\0';
  565.         if(f_gnudump) {         /* Read the entry and delete files
  566.                        that aren't listed in the archive */
  567.             gnu_restore(skipcrud);
  568.  
  569.         } else if(head->header.linkflag==LF_DUMPDIR)
  570.             skip_file((long)(hstat.st_size));
  571.  
  572.  
  573.     again_dir:
  574.         check = mkdir(skipcrud+head->header.name,
  575.                   0300 | (int)hstat.st_mode);
  576.         if (check != 0) {
  577.             if (make_dirs(skipcrud+head->header.name))
  578.                 goto again_dir;
  579.             /* If we're trying to create '.', let it be. */
  580.             if (head->header.name[skipcrud+namelen] == '.' &&
  581.                 (namelen==0 ||
  582.                  head->header.name[skipcrud+namelen-1]=='/'))
  583.                 goto check_perms;
  584.             if(f_gnudump && errno==EEXIST)
  585.                 break;
  586.             msg_perror("Could not make directory %s",skipcrud+head->header.name);
  587.             break;
  588.         }
  589.  
  590.     check_perms:
  591.         if (0300 != (0300 & (int) hstat.st_mode)) {
  592.             hstat.st_mode |= 0300;
  593.             msg("Added write and execute permission to directory %s",
  594.               skipcrud+head->header.name);
  595.         }
  596.  
  597.         goto set_filestat;
  598.         /* FIXME, Remember timestamps for after files created? */
  599.         /* FIXME, change mode after files created (if was R/O dir) */
  600.     case LF_VOLHDR:
  601.         if(f_verbose) {
  602.             printf("Reading %s\n",head->header.name);
  603.         }
  604.         break;
  605.  
  606.     case LF_MULTIVOL:
  607.         msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
  608.         skip_file((long)hstat.st_size);
  609.         break;
  610.  
  611.     }
  612.  
  613.     /* We don't need to save it any longer. */
  614.     saverec((union record **) 0);   /* Unsave it */
  615. }
  616.  
  617. /*
  618.  * After a file/link/symlink/dir creation has failed, see if
  619.  * it's because some required directory was not present, and if
  620.  * so, create all required dirs.
  621.  */
  622. int
  623. make_dirs(pathname)
  624.     char *pathname;
  625. {
  626.     char *p;            /* Points into path */
  627.     int madeone = 0;        /* Did we do anything yet? */
  628.     int save_errno = errno;     /* Remember caller's errno */
  629.     int check;
  630.  
  631.     if (errno != ENOENT)
  632.         return 0;        /* Not our problem */
  633.  
  634.     for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
  635.         /* Avoid mkdir of empty string, if leading or double '/' */
  636.         if (p == pathname || p[-1] == '/')
  637.             continue;
  638.         /* Avoid mkdir where last part of path is '.' */
  639.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  640.             continue;
  641.         *p = 0;             /* Truncate the path there */
  642.         check = mkdir (pathname, 0777); /* Try to create it as a dir */
  643.         if (check == 0) {
  644.             /* Fix ownership */
  645.             if (we_are_root) {
  646.                 if (chown(pathname, hstat.st_uid,
  647.                       hstat.st_gid) < 0) {
  648.                     msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
  649.                 }
  650.             }
  651.             pr_mkdir(pathname, p-pathname, notumask&0777);
  652.             madeone++;        /* Remember if we made one */
  653.             *p = '/';
  654.             continue;
  655.         }
  656.         *p = '/';
  657.         if (errno == EEXIST)            /* Directory already exists */
  658.             continue;
  659.         /*
  660.          * Some other error in the mkdir.  We return to the caller.
  661.          */
  662.         break;
  663.     }
  664.  
  665.     errno = save_errno;        /* Restore caller's errno */
  666.     return madeone;         /* Tell them to retry if we made one */
  667. }
  668.  
  669. extract_sparse_file(fd, sizeleft, totalsize, name)
  670.     int    fd;
  671.     long    *sizeleft,
  672.         totalsize;
  673.     char    *name;
  674. {
  675.     register char    *data;
  676.     union record    *datarec;
  677.     int    sparse_ind = 0;
  678.     int    written,
  679.         count;
  680.  
  681.     /* assuming sizeleft is initially totalsize */
  682.  
  683.  
  684.     while (*sizeleft > 0) {
  685.         datarec = findrec();
  686.         if (datarec == NULL) {
  687.             msg("Unexpected EOF on archive file");
  688.             return;
  689.         }
  690.         lseek(fd, sparsearray[sparse_ind].offset, 0);
  691.         written = sparsearray[sparse_ind++].numbytes;
  692.         while (written > RECORDSIZE) {
  693.             count = write(fd, datarec->charptr, RECORDSIZE);
  694.             if (count < 0)
  695.                 msg_perror("couldn't write to file %s", name);
  696.             written -= count;
  697.             *sizeleft -= count;
  698.             userec(datarec);
  699.             datarec = findrec();
  700.         }
  701.  
  702.         count = write(fd, datarec->charptr, written);
  703.  
  704.         if (count < 0) {
  705.             msg_perror("couldn't write to file %s", name);
  706.         } else if (count != written) {
  707.             msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
  708.             skip_file((long) (*sizeleft));
  709.         }
  710.  
  711.         written -= count;
  712.         *sizeleft -= count;
  713.         userec(datarec);
  714.     }
  715.     free(sparsearray);
  716. /*    if (end_nulls) {
  717.         register int i;
  718.  
  719.         printf("%d\n", (int) end_nulls);
  720.         for (i = 0; i < end_nulls; i++)
  721.             write(fd, "\000", 1);
  722.     }*/
  723.     userec(datarec);
  724. }
  725.